﻿using GBLServices;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Text.RegularExpressions;
using System.Threading.Tasks;

namespace easyui.AuthHelper
{
    /// <summary>
    /// 权限授权处理器，继承AuthorizationHandler ，并且需要一个权限必要参数
    /// </summary>
    public class PermissionHandler : AuthorizationHandler<PermissionRequirement>
    {
        readonly MenuServices _Menu;
        readonly IHttpContextAccessor _accessor;
        /// <summary>
        /// 验证方案提供对象
        /// </summary>
        IAuthenticationSchemeProvider _Schemes { get; set; }
        public PermissionHandler(IAuthenticationSchemeProvider schemes, MenuServices menu,IHttpContextAccessor accessor)
        {
            _Menu = menu;
            _Schemes = schemes;
            _accessor = accessor;
        }
        protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, PermissionRequirement requirement)
        {

            //var httpContext = (context.Resource as Microsoft.AspNetCore.Mvc.Filters.AuthorizationFilterContext).HttpContext;
            var httpContext = _accessor.HttpContext;
            //请求Url
            if (httpContext != null)
            {
                var requestUrl = httpContext.Request.Path.Value.ToLower();
                //判断请求是否停止
                var handlers = httpContext.RequestServices.GetRequiredService<IAuthenticationHandlerProvider>();
                foreach (var scheme in await _Schemes.GetRequestHandlerSchemesAsync())
                {
                    if(await handlers.GetHandlerAsync(httpContext,scheme.Name) is IAuthenticationRequestHandler handler && await handler.HandleRequestAsync())
                    {
                        context.Fail();
                        return;
                    }
                }

                //判断请求是否拥有凭据，即有没有登录
                var defaultAuthenticate = await _Schemes.GetDefaultAuthenticateSchemeAsync();
                if (defaultAuthenticate != null)
                {
                    var result = await httpContext.AuthenticateAsync(defaultAuthenticate.Name);
                    //result?.Principal != null 即为登录成功
                    if (result?.Principal != null)
                    {
                        httpContext.User = result.Principal;

                        /*前后端分离时可以启用
                        var data = await _Menu.GetMenuAsync(1);
                        var list = (from item in data
                                    where item.module != 0
                                    select new PermissionItem
                                    {
                                        Role = item.rolename,
                                        Url = item.path
                                    }).ToList();
                        requirement.Permissions = list;
                        */

                        //获取当前用户的角色信息
                        var currentUserRoles = new List<string>();
                        currentUserRoles = (from item in httpContext.User.Claims
                                            where item.Type == requirement.ClaimType
                                            select item.Value).ToList();

                        bool isMatchRole = false;
                        var permissionRoles = requirement.Permissions.Where(w => currentUserRoles.Contains(w.Role));
                        foreach (var item in permissionRoles)
                        {
                            try
                            {
                                if (Regex.IsMatch(requestUrl, "^/?"+(item.Url == null ? "" : item.Url.ToString().Trim().ToLower())+ "(\\?.+)?$",RegexOptions.IgnoreCase))
                                {
                                    isMatchRole = true;
                                    break;
                                }
                            }
                            catch (Exception ex)
                            { }
                        }

                        if (currentUserRoles.Count <= 0 || !isMatchRole)
                        {
                            context.Fail();
                            return;
                        }

                        var isExp = false;

                        //jwt
                        var claimExp = httpContext.User.Claims.SingleOrDefault(s => s.Type == ClaimTypes.Expiration)?.Value;
                        if(!string.IsNullOrEmpty(claimExp) && DateTime.Parse(claimExp) >= DateTime.Now)
                        {
                            isExp = true;
                        }
                        if (isExp)
                        {
                            context.Succeed(requirement);
                        }
                        else
                        {
                            context.Fail();
                            return;
                        }
                        return;
                    }
                }
                //判断有没登录时，是否访问登录的url，并且是Post请求，并且是form表单提交类型，否则为失败
                if (!requestUrl.Equals(requirement.LoginPath.ToLower(), StringComparison.Ordinal) &&
                    (!httpContext.Request.Method.Equals("POST") || !httpContext.Request.HasFormContentType))
                {
                    context.Fail();
                    return;
                }
            }
            //context.Succeed(requirement);
        }
    }
}
